package com.api.controller;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import cn.hutool.core.convert.ConverterRegistry;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.common.apiResult.ApiController;
import com.common.apiResult.ApiResult;
import com.api.domain.ApiAccount;
import com.api.paramsVO.LoginParamsVO;
import com.api.service.IApiAccountService;
import com.common.annotation.PassToken;
import com.common.exception.ApiException;
import com.common.utils.StringUtils;
import com.framework.LoginAccount;
import com.framework.redis.RedisCache;
import com.framework.service.TokenService;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @ClassName LoginController
 * @Description 小程序登录授权
 * @Date 2020/9/26 14:35
 * Create By Renbowen
 */
@RequestMapping(value = "/api/mini")
@RestController
@Slf4j
public class MiniProgramLoginController extends ApiController {

    // wxJava小程序操作API
    private final WxMaService wxService;
    // 用户服务
    private final IApiAccountService accountService;
    // token服务
    private final TokenService tokenService;
    // redis缓存服务
    private final RedisCache redisCache;

    public MiniProgramLoginController(WxMaService wxService, IApiAccountService accountService, TokenService tokenService, RedisCache redisCache) {
        this.wxService = wxService;
        this.accountService = accountService;
        this.tokenService = tokenService;
        this.redisCache = redisCache;
    }

    private final ConverterRegistry converterRegistry = ConverterRegistry.getInstance();


    /**
     *  Create By Renbowen
     *  @Date: 2020/9/30 10:46
     *  @Description: 获取当前登录用户信息
     */
    @RequestMapping(value = "/getLoginAccount",method = RequestMethod.GET)
    @PassToken
    public ApiResult getLoginAccount(HttpServletRequest request) {
        // 模拟抛出异常
//        throw new IndexOutOfBoundsException();
        // 模拟抛出自定义异常
        throw new ApiException("模拟自定义异常抛出！");
        //TODO 不用担心会报空指针
        // 在TokenService里抛出了ApiLoginException，
        // 使用ApiExceptionHandlerInterceptor拦截ApiLoginException并返回201错误码，
        // 并且所有自定义抛得异常会返回指定报错信息，所有系统错误，如空指针，下标超出，类型转换失败一系列报错均会返回系统异常
        // 前端可拦截201统一处理登录ApiCode里可以自定义DONT_LOGIN
//        return ApiResult.ok(tokenService.getLoginUser(request).getAccount());
    }

    /**
     * 微信小程序授权登录，颁发token
     *
     * @return
     */
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    @PassToken
    public ApiResult login(@Validated LoginParamsVO params, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            return ApiResult.fail(Objects.requireNonNull(bindingResult.getFieldError()).getDefaultMessage());
        }
        try {
            WxMaJscode2SessionResult session = wxService.getUserService()
                    .getSessionInfo(params.getCode());
            log.info("登录获取到的sessionKey{{}}", session.getSessionKey());
            log.info("登录获取到的openId{{}}", session.getOpenid());
            // 是否绑定手机号标识
            boolean bindingPhoneStatus = false;
            // 用户类型1中介0普通用户
            Integer accountType = 0;
            // 根据openId获取用户信息
            ApiAccount account = accountService.selectApiAccountByWxOpenId(session.getOpenid());
            LoginAccount loginAccount = new LoginAccount();
            // 如果为空，第一次进入 新增用户
            if (account == null) {
                // 解密用户信息
                WxMaUserInfo userInfo = wxService.getUserService()
                        .getUserInfo(session.getSessionKey(), params.getEncryptedData(), params.getIv());
                // 邀请人id
                Long parentId = 0L;
                if (params.getParentId() != null) {
                    parentId = params.getParentId();
                }
                ApiAccount createAccount = ApiAccount.builder()
                        .accountId(IdUtil.getSnowflake(1, 1).nextId())
                        .parentId(parentId)
                        .wxOpenid(userInfo.getOpenId())
                        .sessionKey(session.getSessionKey())
                        .headPortrait(userInfo.getAvatarUrl())
                        .nickName(userInfo.getNickName())
                        .sex(converterRegistry.convert(Integer.class, userInfo.getGender()))
                        .type(0)
                        .delStatus(0)
                        .lastDate(DateUtil.date())
                        .createDate(DateUtil.date())
                        .build();
                int flag = accountService.insertApiAccount(createAccount);
                if (flag < 1) {
                    return ApiResult.fail("新增用户失败！");
                }
                loginAccount.setAccount(createAccount);
            } else {
                // 若已经绑定手机号
                if (StringUtils.isNotBlank(account.getPhone())) {
                    bindingPhoneStatus = true;
                }
                accountType = account.getType();
                loginAccount.setAccount(account);
                // 已存在，更新用户登录时间 更新sessionKey
                accountService.updateApiAccount(ApiAccount.builder()
                        .accountId(account.getAccountId())
                        .sessionKey(session.getSessionKey())
                        .lastDate(DateUtil.date())
                        .build());
            }
            // 强退其他用户
            Collection<String> keys = redisCache.keys(TokenService.LOGIN_TOKEN_KEY + "*");
            for (String key : keys) {
                LoginAccount nowAccount = redisCache.getCacheObject(key);
                if (nowAccount != null) {
                    // 如果登录名等于redis存储的用户登录名
                    if (session.getOpenid().equals(nowAccount.getAccount().getWxOpenid())) {
                        // 退出登录
                        redisCache.deleteObject(TokenService.LOGIN_TOKEN_KEY + nowAccount.getToken());
                    }
                }
            }
            Map<String, Object> resultMap = new HashMap<>();
            resultMap.put("bindingPhoneStatus", bindingPhoneStatus);
            resultMap.put("token", tokenService.createToken(loginAccount));
            resultMap.put("accountType", accountType);
            return ApiResult.ok(resultMap);
        } catch (Exception e) {
            e.printStackTrace();
            return ApiResult.fail(e.getMessage());
        }
    }


    /**
     *  Create By Renbowen
     *  @Date: 2020/9/30 10:46
     *  @Description: 绑定手机号
     */
    @RequestMapping(value = "/bindingPhone", method = RequestMethod.POST)
    @PassToken
    public ApiResult bindingPhone(String phone, HttpServletRequest request){
        if (StringUtils.isBlank(phone)) {
            return ApiResult.fail("手机号码为空！");
        }
        ApiAccount account = tokenService.getLoginUser(request).getAccount();
        int flag = accountService.updateApiAccount(ApiAccount.builder()
                .accountId(account.getAccountId())
                .phone(phone)
                .build());
        if (flag < 1){
            return ApiResult.fail("绑定手机号失败！");
        }
        return ApiResult.ok(account);
    }

    /**
     *  Create By Renbowen
     *  @Date: 2020/9/27 16:47
     *  @Description: 获取sessionKey
     */
    @RequestMapping(value = "/getSessionKey",method = RequestMethod.POST)
    @PassToken
    public ApiResult biography(String code) throws WxErrorException {
        if (StringUtils.isBlank(code)){
            return ApiResult.fail("code为空！");
        }
        WxMaJscode2SessionResult session = wxService.getUserService()
                .getSessionInfo(code);
        return ApiResult.ok(session.getSessionKey());
    }


}
